using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace BNode.Expressions
{
    //By UNeko
    public static class ExpressionExtensions
    {
        // 通用生成器
        private static BinaryExpression BuildExpression(Expression left,Func<Expression, Expression, BinaryExpression> opFunc,params Expression[] right)
        {
            if (right.Length == 0) throw new ArgumentException("给点参数啊笨蛋！", nameof(right));

            // 从右向左淦！先拿最后一个元素当起点
            Expression current = right[^1];

            // 倒着遍历剩下的元素
            for (int i = right.Length - 2; i >= 0; i--)
            {
                current = opFunc(right[i], current); // 把当前元素当左子树插进去
            }

            // 最后把原始左参数挂到最外层
            return opFunc(left, current);
        }

        // 多参数扩展方法
        public static BinaryExpression Assign(this Expression left, params Expression[] right) => BuildExpression(left, Expression.Assign, right);
        public static BinaryExpression Add(this Expression left, params Expression[] right)=> BuildExpression(left, Expression.Add, right);
        public static BinaryExpression Subtract(this Expression left, params Expression[] right)=> BuildExpression(left, Expression.Subtract, right);
        public static BinaryExpression Multiply(this Expression left, params Expression[] right)=> BuildExpression(left, Expression.Multiply, right);
        public static BinaryExpression Divide(this Expression left, params Expression[] right)=> BuildExpression(left, Expression.Divide, right);
        public static BinaryExpression And(this Expression left, params Expression[] right) => BuildExpression(left, Expression.And, right);
        public static BinaryExpression Or(this Expression left, params Expression[] right)=> BuildExpression(left, Expression.Or, right);

        // 常量版本生成器
        private static BinaryExpression BuildExpression(Expression left,Func<Expression, Expression, BinaryExpression> opFunc,params object[] right)
        {
            if (right.Length == 0) throw new ArgumentException("给点参数啊笨蛋！", nameof(right));

            // 从右向左！先拿最后一个元素当起点

            Expression current = right[^1].Constant(); // ^1是C#8的骚操作，等于right.Length-1

            // 倒着遍历剩下的元素
            for (int i = right.Length - 2; i >= 0; i--)
            {
                current = opFunc(right[i].Constant(), current); // 把当前元素当左子树插进去
            }

            // 最后把原始左参数挂到最外层
            return opFunc(left, current);
        }

        // 常量多参数
        public static BinaryExpression Assign(this Expression left, params object[] right) => BuildExpression(left, Expression.Add, right);
        public static BinaryExpression Add(this Expression left, params object[] right)=> BuildExpression(left, Expression.Add, right);
        public static BinaryExpression Subtract(this Expression left, params object[] right)=> BuildExpression(left, Expression.Subtract, right);
        public static BinaryExpression Multiply(this Expression left, params object[] right) => BuildExpression(left, Expression.Multiply, right);
        public static BinaryExpression Divide(this Expression left, params object[] right)=> BuildExpression(left, Expression.Divide, right);
        public static BinaryExpression And(this Expression left, params object[] right)=> BuildExpression(left, Expression.And, right);
        public static BinaryExpression Or(this Expression left, params object[] right) => BuildExpression(left, Expression.Or, right);
        public static BinaryExpression LessThan(this Expression left, Expression right)=> Expression.LessThan(left, right);
        public static BinaryExpression GreaterThan(this Expression left, Expression right)=> Expression.GreaterThan(left, right);
        public static BinaryExpression LessThanOrEqual(this Expression left, Expression right)=> Expression.LessThanOrEqual(left, right);
        public static BinaryExpression GreaterThanOrEqual(this Expression left, Expression right)=> Expression.GreaterThanOrEqual(left, right);
        public static BinaryExpression Equal(this Expression left, Expression right)=> Expression.Equal(left, right);
        public static BinaryExpression NotEqual(this Expression left, Expression right)=> Expression.NotEqual(left, right);
        public static ConstantExpression Constant(this object obj) => Expression.Constant(obj);
        public static BinaryExpression LessThan(this Expression left, object right) => Expression.LessThan(left, right.Constant());
        public static BinaryExpression GreaterThan(this Expression left, object right) => Expression.GreaterThan(left, right.Constant());
        public static BinaryExpression LessThanOrEqual(this Expression left, object right) => Expression.LessThanOrEqual(left, right.Constant());
        public static BinaryExpression GreaterThanOrEqual(this Expression left, object right) => Expression.GreaterThanOrEqual(left, right.Constant());
        public static BinaryExpression Equal(this Expression left, object right) => Expression.Equal(left, right.Constant());
        public static BinaryExpression NotEqual(this Expression left, object right) => Expression.NotEqual(left, right.Constant());
        public static MemberExpression Property(this Expression para, string name) => Expression.Property(para, name);
        public static MemberExpression Property(this Expression para, PropertyInfo info) => Expression.Property(para,info);
        public static MemberExpression Field(this Expression para, string name) => Expression.Field(para, name);
        public static MemberExpression Field(this Expression para, FieldInfo info) => Expression.Field(para, info);
        public static IndexExpression MakeIndex(this Expression instance, PropertyInfo propertyInfo, IEnumerable<Expression> args)
            => Expression.MakeIndex(instance, propertyInfo, args);
        public static IndexExpression MakeIndex(this Expression instance, Type[] types, IEnumerable<Expression> args)
        {
            var propertyInfo = instance.Type.GetProperty("Item", types);
            return Expression.MakeIndex(instance, propertyInfo, args);
        }
        public static IndexExpression MakeIndex(this Expression instance, Type[] types, params Expression[] args)
        {
            var propertyInfo = instance.Type.GetProperty("Item", types);
            return Expression.MakeIndex(instance, propertyInfo, args);
        }
        /// <summary>
        /// 从目标上获取相应Field
        /// </summary>
        public static MemberAssignment BindSource(this FieldInfo member,ParameterExpression source)=>Expression.Bind(member,Expression.Field(source,member));
        public static MemberAssignment BindSource(this PropertyInfo member, ParameterExpression source) => Expression.Bind(member, Expression.Property(source, member));
        public static MemberAssignment Bind(this MemberInfo member, Expression value) => Expression.Bind(member, value);
        public static IndexExpression ArrayAccess(this Expression array, Expression index) => Expression.ArrayAccess(array, index);
        public static IndexExpression ArrayAccess(this Expression array, object index) => Expression.ArrayAccess(array, index.Constant());
        public static UnaryExpression Quote(this Expression expression) => Expression.Quote(expression);
        public static NewExpression New(this Type type) => Expression.New(type);
        public static NewArrayExpression NewArrayBounds(this Type elementType, IEnumerable<Expression> bounds) 
            => Expression.NewArrayBounds(elementType, bounds);
        public static NewArrayExpression NewArrayBounds(this Type elementType, params Expression[] bounds)
            => Expression.NewArrayBounds(elementType, bounds);
        public static NewExpression New(this Type type,Type[] paramTypes,IEnumerable<Expression> args)
            => Expression.New(type.GetConstructor(paramTypes), args);
        public static NewArrayExpression NewArrayInit(this Type elementType, IEnumerable<Expression> initializers)
            => Expression.NewArrayInit(elementType, initializers);
        public static NewArrayExpression NewArrayInit(this Type elementType, params Expression[] initializers) 
            => Expression.NewArrayInit(elementType, initializers);
        public static NewExpression New(this ConstructorInfo constructor, IEnumerable<Expression> args)
            => Expression.New(constructor, args);
        public static NewExpression New(this Type type, Type[] paramTypes, params Expression[] args)
            => Expression.New(type.GetConstructor(paramTypes), args);
        public static NewExpression New(this ConstructorInfo constructor, params Expression[] args)
            => Expression.New(constructor, args);
        /// <summary>
        /// 为Array，Stack，List这类有相似的构造函数(int size)服务
        /// </summary>
        public static Expression NewForSize<SizeType>(this Type type, Expression size)
        {
            if(type.IsArray) return Expression.NewArrayBounds(type.GetElementType(), size);
            return Expression.New(type.GetConstructor(new Type[] { typeof(SizeType) }), size);
        }
        public static MemberInitExpression MemberInit(this NewExpression newExpression, IEnumerable<MemberBinding> bindings)
            => Expression.MemberInit(newExpression, bindings);
        /// <summary>
        /// x++
        /// </summary>
        public static UnaryExpression PostIncrementAssign(this Expression expression) => Expression.PostIncrementAssign(expression);
        /// <summary>
        /// ++x
        /// </summary>
        public static UnaryExpression PreIncrementAssign(this Expression expression) => Expression.PreIncrementAssign(expression);
        /// <summary>
        /// x--
        /// </summary>
        public static UnaryExpression PostDecrementAssign(this Expression expression) => Expression.PostDecrementAssign(expression);
        /// <summary>
        /// --x
        /// </summary>
        public static UnaryExpression PreDecrementAssign(this Expression expression) => Expression.PreDecrementAssign(expression);
        public static Expression Clamp(this Expression value, Expression min, Expression max)
            =>Expression.Condition(Expression.LessThan(value, min), min,Expression.Condition(Expression.GreaterThan(value, max), max, value));
        public static Expression Clamp(this Expression value, object min, object max)
            => value.Clamp(min.Constant(), max.Constant());
        public static Expression ListGet(this Expression list, Expression index)
        {
            var elementType = list.Type.GetGenericArguments()[0];
            // 动态构建IList<T>
            var genericIListType = typeof(IList<>).MakeGenericType(elementType);

            var getMethod = BCache.BTypeCache.MethodInfo($"IList<{elementType.Name}>.get_Item", _=>genericIListType.GetMethod("get_Item"));
            //var getMethod = genericIListType.GetMethod("get_Item");
            return Expression.Call(list, getMethod, index);
        }
        public static Expression ListGet(this Expression list, object index) => list.ListGet(index.Constant());
        public static Expression ListSet(this Expression list, Expression index, Expression value)
        {
            var elementType = list.Type.GetGenericArguments()[0];
            var iListType = typeof(IList<>).MakeGenericType(elementType);
            var setMethod = BCache.BTypeCache.MethodInfo($"IList<{elementType.Name}>.set_Item", _=>iListType.GetMethod("set_Item"));
            //var setMethod = iListType.GetMethod("set_Item")!;

            // 自动类型转换（重要！）
            var convertedValue = value.EnsureTypeCompatibility(elementType);

            return Expression.Call(list, setMethod, index, convertedValue);
        }
        public static Expression ListSet(this Expression list, object index, object value)=> list.ListSet(index.Constant(), value.Constant());
        public static Expression ListGet<T>(this Expression list, Expression index)
        {
            // 抓取List的get_Item方法
            var getMethod = BCache.BTypeCache.MethodInfo($"IList<{typeof(T).Name}>.get_Item", _=>typeof(T).GetMethod("get_Item"));
            //var getMethod = typeof(List<T>).GetMethod("get_Item")!;
            return Expression.Call(list,getMethod,index);
        }
        public static Expression ListGet<T>(this Expression list, object index) => list.ListGet<T>(index.Constant());
        public static Expression ListSet<T>(this Expression list, Expression index, Expression value)
        {
            // 抓取List的set_Item方法
            var setMethod = BCache.BTypeCache.MethodInfo($"IList<{typeof(T).Name}>.set_Item", _=>typeof(T).GetMethod("set_Item"));
            //var setMethod = typeof(List<T>).GetMethod("set_Item")!;
            return Expression.Call(list,setMethod,index,value);
        }
        public static Expression ListSet<T>(this Expression list, object index, object value) => list.ListSet<T>(index.Constant(),value.Constant());
        public static IndexExpression Index(this Expression expression, Expression index) => expression.MakeIndex(new Type[] {typeof(int) },index);
        public static IndexExpression Index(this Expression expression, object index) => expression.MakeIndex(new Type[] { typeof(int) }, index.Constant());
        public static Expression EnsureConvert(this Expression expression,Type targetType, MethodInfo method = null)
        {
            if (expression.Type == targetType) return expression;
            if (method == null)
            {
                expression = expression.EnsureTypeCompatibility(targetType);
            }
            else
            {
                //Convert里只能用静态方法
                expression = method.IsStatic
                    ? Expression.Convert(expression, targetType, method)
                    : Expression.Call(expression, method);
            }
            return expression;
        }
        public static Expression EnsureConvert<TTarget>(this Expression expression, MethodInfo method = null) 
            => expression.EnsureConvert(typeof(TTarget), method);
        public static Expression EnsureConvert<T, TTarget>(this Expression expression, Func<T, TTarget> convertFunc) 
            => expression.EnsureConvert(typeof(TTarget), convertFunc.Method);

        public static InvocationExpression Invoke<D>(this Expression<D> lambda, params Expression[] args) where D:Delegate
            => Expression.Invoke(lambda, Array.AsReadOnly(args));

        public static Expression EnsureTypeCompatibility(this Expression expr, Type targetType)
        {
            if (expr.Type == targetType) return expr;

            // 1. 处理装箱/拆箱
            if ((expr.Type.IsValueType && targetType == typeof(object))|| (expr.Type==typeof(object) && targetType.IsValueType))
            {
                return Expression.Convert(expr, targetType);
            }

            // 2. 处理继承关系
            if (targetType.IsAssignableFrom(expr.Type))return Expression.TypeAs(expr, targetType);

            // 3. 查找隐式转换运算符（静态和实例）
            var conversionMethod = ExpressionUtility.FindStaticConversionMethod(expr.Type, targetType);
            if (conversionMethod != null)
            {
                return conversionMethod.IsStatic
                    ? Expression.Call(conversionMethod, expr)
                    : Expression.Call(expr, conversionMethod);
            }

            //如果参数本身就是目标
            if (targetType == typeof(Expression) && expr.NodeType == ExpressionType.Parameter && (!typeof(Expression).IsAssignableFrom(expr.Type)))
            {
                var c = Expression.Constant(expr, typeof(Expression));
                return c;
            }

            // 最后尝试强制转换
            return Expression.Convert(expr, targetType);
        }
    }
    public static class ExpressionUtility
    {
        public static bool IsNullOrEmpty(Expression expression)
        {
            if (expression == null) return true;
            if (expression == Expression.Empty()) return true;
            return false;
        }
        public static MethodInfo FindStaticConversionMethodCore(Type source, Type target)
        {
            // 查找定义的静态转换方法
            var flags = BindingFlags.Public | BindingFlags.Static;

            var staticMethod = source.GetMethod("op_Implicit", flags, null, new[] { source }, null)
                ?? target.GetMethod("op_Implicit", flags, null, new[] { source }, null)
                ?? source.GetMethod("op_Explicit", flags, null, new[] { source }, null)
                ?? target.GetMethod("op_Explicit", flags, null, new[] { source }, null);

            return staticMethod;
        }
    }
}





